<?php

namespace app\admin\controller\yuncunchu;

use app\common\controller\Backend;
use app\common\service\YuncunchuService;
use think\Exception;

/**
 * 文件上传API
 */
class Upload extends Backend
{
    protected $noNeedLogin = [];
    protected $noNeedRight = ['*'];

    /**
     * 单文件上传
     */
    public function index()
    {
        // 直接使用PHP的$_FILES，避免ThinkPHP的文件处理
        if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
            $this->error('文件上传失败');
        }
        
        $uploadedFile = $_FILES['file'];
        $configId = $this->request->post('config_id');
        $module = $this->request->post('module', 'admin');
        $action = $this->request->post('action', 'upload');
        
        try {
            // 检查文件大小
            $maxSize = 50 * 1024 * 1024; // 50MB
            if ($uploadedFile['size'] > $maxSize) {
                $this->error('文件大小超过限制（最大允许：50MB）');
            }
            
            // 检查文件类型
            $allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'zip', 'rar', 'wav', 'mp4', 'mp3', 'webm'];
            $extension = strtolower(pathinfo($uploadedFile['name'], PATHINFO_EXTENSION));
            if (!in_array($extension, $allowedTypes)) {
                $this->error('不支持的文件类型：' . $extension);
            }
            
            // 直接处理文件，完全避免框架方法
            $result = $this->processDirectFileUpload($uploadedFile, $configId, $module, $action);
            
            if ($result['success']) {
                $this->success('上传成功', null, $result);
            } else {
                $this->error($result['message']);
            }
        } catch (Exception $e) {
            $this->error('上传失败：' . $e->getMessage());
        }
    }
    
    /**
     * 公共文件上传方法，供外部调用
     */
    public function uploadFile($uploadedFile, $configId, $module, $action)
    {
        return $this->processDirectFileUpload($uploadedFile, $configId, $module, $action);
    }
    
    /**
     * 直接处理文件上传，完全不使用框架方法
     */
    protected function processDirectFileUpload($uploadedFile, $configId, $module, $action)
    {
        // 获取配置
        $config = \app\admin\model\yuncunchu\Config::find($configId);
        if (!$config) {
            return ['success' => false, 'message' => '存储配置不存在'];
        }
        
        // 生成文件信息
        $extension = strtolower(pathinfo($uploadedFile['name'], PATHINFO_EXTENSION));
        $originalName = pathinfo($uploadedFile['name'], PATHINFO_FILENAME);
        
        // 生成唯一文件名（保留原文件名的一部分）
        $uniqueId = substr(md5(uniqid(mt_rand(), true)), 0, 8);
        $fileName = $originalName . '_' . $uniqueId . '.' . $extension;
        
        // 构建合理的目录结构
        $filePath = $this->buildFilePath($module, $action, $fileName, $config);
        
        // 读取文件内容
        $content = file_get_contents($uploadedFile['tmp_name']);
        if ($content === false) {
            return ['success' => false, 'message' => '无法读取文件内容'];
        }
        
        // 计算哈希值
        $md5 = md5($content);
        $sha1 = sha1($content);
        
        // 根据存储类型处理
        switch ($config->type) {
            case 'local':
                return $this->uploadToLocalDirect($content, $filePath, $fileName, $uploadedFile, $config, $module, $action, $md5, $sha1);
            case 'qiniu':
                $result = $this->uploadToQiniuDirect($content, $filePath, $fileName, $uploadedFile, $config, $module, $action, $md5, $sha1);
                break;
            case 'aliyun_oss':
                $result = $this->uploadToAliyunOSS($content, $filePath, $fileName, $uploadedFile, $config, $module, $action, $md5, $sha1);
                break;
            case 'tencent_cos':
                $result = $this->uploadToTencentCOS($content, $filePath, $fileName, $uploadedFile, $config, $module, $action, $md5, $sha1);
                break;
            default:
                return ['success' => false, 'message' => '不支持的存储类型：' . $config->type];
        }
        
        // 如果云端上传成功且启用了本地备份，则同时保存到本地
        if ($result['success'] && $config->type !== 'local') {
            $configData = $config->config;
            if (isset($configData['local_backup']) && $configData['local_backup'] == '1') {
                $this->saveLocalBackup($content, $filePath, $fileName, $uploadedFile, $config, $module, $action, $md5, $sha1);
            }
        }
        
        return $result;
    }
    
    /**
     * 直接上传到本地存储
     */
    protected function uploadToLocalDirect($content, $filePath, $fileName, $uploadedFile, $config, $module, $action, $md5, $sha1)
    {
        $configData = $config->config;
        $uploadPath = $configData['path'] ?? '/uploads';
        $uploadUrl = $configData['url'] ?? '/uploads';
        
        // 确保目录存在
        $fullPath = ROOT_PATH . 'public' . $uploadPath . '/' . $filePath;
        $dir = dirname($fullPath);
        
        if (!is_dir($dir)) {
            if (!mkdir($dir, 0755, true)) {
                return ['success' => false, 'message' => '无法创建目录'];
            }
        }
        
        // 写入文件
        if (file_put_contents($fullPath, $content) === false) {
            return ['success' => false, 'message' => '文件写入失败'];
        }
        
        // 保存到数据库
        $fileUrl = $uploadUrl . '/' . $filePath;
        $fileRecord = $this->saveFileRecordDirect($uploadedFile, $filePath, $fileUrl, $config->id, $module, $action, $md5, $sha1);
        
        return [
            'success' => true,
            'file_id' => $fileRecord->id,
            'file_url' => $fileUrl,
            'file_name' => $fileName,
            'original_name' => $uploadedFile['name'],
            'file_size' => $uploadedFile['size'],
            'file_type' => $uploadedFile['type']
        ];
    }
    
    /**
     * 直接上传到七牛云
     */
    protected function uploadToQiniuDirect($content, $filePath, $fileName, $uploadedFile, $config, $module, $action, $md5, $sha1)
    {
        $configData = $config->config;
        
        try {
            error_log('=== 开始七牛云上传 ===');
            error_log('文件路径: ' . $filePath);
            error_log('文件名: ' . $fileName);
            error_log('文件大小: ' . strlen($content));
            error_log('Access Key: ' . substr($configData['access_key'], 0, 8) . '...');
            error_log('Bucket: ' . $configData['bucket']);
            error_log('Domain: ' . $configData['domain']);
            
            // 使用七牛云SDK上传
            $auth = new \Qiniu\Auth($configData['access_key'], $configData['secret_key']);
            $token = $auth->uploadToken($configData['bucket']);
            
            error_log('上传Token生成成功，长度: ' . strlen($token));
            
            $uploadMgr = new \Qiniu\Storage\UploadManager();
            list($ret, $err) = $uploadMgr->put($token, $filePath, $content);
            
            if ($err !== null) {
                error_log('七牛云上传失败: ' . $err->message());
                error_log('错误代码: ' . $err->code());
                return ['success' => false, 'message' => '七牛云上传失败：' . $err->message()];
            }
            
            error_log('七牛云上传成功: ' . json_encode($ret));
            
            // 生成文件URL
            $fileUrl = $configData['domain'] . '/' . $filePath;
            
            // 保存到数据库
            $fileRecord = $this->saveFileRecordDirect($uploadedFile, $filePath, $fileUrl, $config->id, $module, $action, $md5, $sha1);
            
            return [
                'success' => true,
                'file_id' => $fileRecord->id,
                'file_url' => $fileUrl,
                'file_name' => $fileName,
                'original_name' => $uploadedFile['name'],
                'file_size' => $uploadedFile['size'],
                'file_type' => $uploadedFile['type']
            ];
        } catch (Exception $e) {
            error_log('七牛云上传异常: ' . $e->getMessage());
            error_log('异常堆栈: ' . $e->getTraceAsString());
            return ['success' => false, 'message' => '七牛云上传失败：' . $e->getMessage()];
        }
    }
    
    /**
     * 上传到阿里云OSS
     */
    protected function uploadToAliyunOSS($content, $filePath, $fileName, $uploadedFile, $config, $module, $action, $md5, $sha1)
    {
        $configData = $config->config;
        
        try {
            // 使用阿里云OSS SDK上传
            $ossClient = new \OSS\OssClient(
                $configData['access_key_id'],
                $configData['access_key_secret'],
                $configData['endpoint']
            );
            
            // 上传文件到OSS
            $result = $ossClient->putObject($configData['bucket'], $filePath, $content);
            
            // 生成文件URL
            if (isset($configData['domain']) && !empty($configData['domain'])) {
                $fileUrl = rtrim($configData['domain'], '/') . '/' . $filePath;
            } else {
                $fileUrl = $result['info']['url'];
            }
            
            // 保存到数据库
            $fileRecord = $this->saveFileRecordDirect($uploadedFile, $filePath, $fileUrl, $config->id, $module, $action, $md5, $sha1);
            
            return [
                'success' => true,
                'file_id' => $fileRecord->id,
                'file_url' => $fileUrl,
                'file_name' => $fileName,
                'original_name' => $uploadedFile['name'],
                'file_size' => $uploadedFile['size'],
                'file_type' => $uploadedFile['type']
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => '阿里云OSS上传失败：' . $e->getMessage()];
        }
    }
    
    /**
     * 上传到腾讯云COS
     */
    protected function uploadToTencentCOS($content, $filePath, $fileName, $uploadedFile, $config, $module, $action, $md5, $sha1)
    {
        $configData = $config->config;
        
        try {
            // 使用腾讯云COS SDK上传
            $cosClient = new \Qcloud\Cos\Client([
                'region' => $configData['region'],
                'credentials' => [
                    'secretId' => $configData['secret_id'],
                    'secretKey' => $configData['secret_key'],
                ]
            ]);
            
            // 上传文件到COS
            $result = $cosClient->putObject([
                'Bucket' => $configData['bucket'],
                'Key' => $filePath,
                'Body' => $content
            ]);
            
            // 生成文件URL
            if (isset($configData['domain']) && !empty($configData['domain'])) {
                $fileUrl = rtrim($configData['domain'], '/') . '/' . $filePath;
            } else {
                $fileUrl = $result['ObjectURL'];
            }
            
            // 保存到数据库
            $fileRecord = $this->saveFileRecordDirect($uploadedFile, $filePath, $fileUrl, $config->id, $module, $action, $md5, $sha1);
            
            return [
                'success' => true,
                'file_id' => $fileRecord->id,
                'file_url' => $fileUrl,
                'file_name' => $fileName,
                'original_name' => $uploadedFile['name'],
                'file_size' => $uploadedFile['size'],
                'file_type' => $uploadedFile['type']
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => '腾讯云COS上传失败：' . $e->getMessage()];
        }
    }

    /**
     * 构建文件路径
     */
    protected function buildFilePath($module, $action, $fileName, $config = null)
    {
        $date = date('Y/m/d');
        $time = date('H');
        
        // 获取配置中的目录结构设置
        if (!$config) {
            $config = \app\admin\model\yuncunchu\Config::getDefaultConfig();
        }
        $configData = $config ? $config->config : [];
        $directoryStructure = $configData['directory_structure'] ?? 'module/action/date';
        
        // 根据配置构建目录结构
        $pathParts = [];
        
        if (strpos($directoryStructure, 'module') !== false) {
            $pathParts[] = $module;
        }
        if (strpos($directoryStructure, 'action') !== false) {
            $pathParts[] = $action;
        }
        if (strpos($directoryStructure, 'date') !== false) {
            $pathParts[] = $date;
        }
        if (strpos($directoryStructure, 'hour') !== false) {
            $pathParts[] = $time;
        }
        
        // 如果没有配置，使用默认结构
        if (empty($pathParts)) {
            $pathParts = [$module, $action, $date];
        }
        
        $directory = implode('/', $pathParts);
        return $directory . '/' . $fileName;
    }
    
    /**
     * 保存本地备份
     */
    protected function saveLocalBackup($content, $filePath, $fileName, $uploadedFile, $config, $module, $action, $md5, $sha1)
    {
        try {
            // 本地备份路径
            $backupPath = '/uploads/backup';
            $fullPath = ROOT_PATH . 'public' . $backupPath . '/' . $filePath;
            $dir = dirname($fullPath);
            
            // 确保目录存在
            if (!is_dir($dir)) {
                if (!mkdir($dir, 0755, true)) {
                    // 本地备份失败不影响主上传流程，只记录日志
                    error_log('云存储本地备份目录创建失败：' . $dir);
                    return false;
                }
            }
            
            // 写入文件
            if (file_put_contents($fullPath, $content) === false) {
                error_log('云存储本地备份文件写入失败：' . $fullPath);
                return false;
            }
            
            // 记录备份信息到数据库
            $backupFileUrl = $backupPath . '/' . $filePath;
            $backupRecord = new \app\admin\model\yuncunchu\File();
            $backupRecord->save([
                'config_id' => $config->id,
                'original_name' => $uploadedFile['name'],
                'file_name' => $fileName,
                'file_path' => $filePath,
                'file_url' => $backupFileUrl,
                'file_size' => $uploadedFile['size'],
                'file_type' => $uploadedFile['type'],
                'mime_type' => $uploadedFile['type'],
                'extension' => strtolower(pathinfo($uploadedFile['name'], PATHINFO_EXTENSION)),
                'md5' => $md5,
                'sha1' => $sha1,
                'upload_module' => $module,
                'upload_action' => $action,
                'is_backup' => 1, // 标记为备份文件
                'createtime' => time(),
                'updatetime' => time()
            ]);
            
            return true;
        } catch (Exception $e) {
            // 本地备份失败不影响主上传流程，只记录日志
            error_log('云存储本地备份失败：' . $e->getMessage());
            return false;
        }
    }

    /**
     * 直接保存文件记录到数据库
     */
    protected function saveFileRecordDirect($uploadedFile, $filePath, $fileUrl, $configId, $module, $action, $md5, $sha1)
    {
        $data = [
            'config_id' => $configId,
            'original_name' => $uploadedFile['name'],
            'file_name' => basename($filePath),
            'file_path' => $filePath,
            'file_url' => $fileUrl,
            'file_size' => $uploadedFile['size'],
            'file_type' => $uploadedFile['type'],
            'mime_type' => $uploadedFile['type'],
            'extension' => strtolower(pathinfo($uploadedFile['name'], PATHINFO_EXTENSION)),
            'md5' => $md5,
            'sha1' => $sha1,
            'upload_module' => $module,
            'upload_action' => $action,
            'user_id' => session('user.id'),
            'admin_id' => session('admin.id'),
            'status' => 1
        ];
        
        return \app\admin\model\yuncunchu\File::create($data);
    }
    
    /**
     * 处理文件上传
     */
    protected function processFileUpload($file, $configId, $module, $action)
    {
        // 获取配置
        $config = \app\admin\model\yuncunchu\Config::find($configId);
        if (!$config) {
            return ['success' => false, 'message' => '存储配置不存在'];
        }
        
        // 生成文件信息
        $extension = strtolower($file->getOriginalExtension());
        $fileName = md5(uniqid(mt_rand(), true)) . '.' . $extension;
        $date = date('Y/m/d');
        $filePath = $date . '/' . $fileName;
        
        // 获取文件内容
        $content = $file->get();
        if ($content === false) {
            return ['success' => false, 'message' => '无法读取文件内容'];
        }
        
        // 计算哈希值
        $md5 = md5($content);
        $sha1 = sha1($content);
        
        // 根据存储类型处理
        switch ($config->type) {
            case 'local':
                return $this->uploadToLocal($content, $filePath, $fileName, $file, $config, $module, $action, $md5, $sha1);
            case 'qiniu':
                return $this->uploadToQiniu($content, $filePath, $fileName, $file, $config, $module, $action, $md5, $sha1);
            default:
                return ['success' => false, 'message' => '不支持的存储类型'];
        }
    }
    
    /**
     * 上传到本地存储
     */
    protected function uploadToLocal($content, $filePath, $fileName, $file, $config, $module, $action, $md5, $sha1)
    {
        $configData = $config->config;
        $uploadPath = $configData['path'] ?? '/uploads';
        $uploadUrl = $configData['url'] ?? '/uploads';
        
        // 确保目录存在
        $fullPath = ROOT_PATH . 'public' . $uploadPath . '/' . $filePath;
        $dir = dirname($fullPath);
        
        if (!is_dir($dir)) {
            if (!mkdir($dir, 0755, true)) {
                return ['success' => false, 'message' => '无法创建目录'];
            }
        }
        
        // 写入文件
        if (file_put_contents($fullPath, $content) === false) {
            return ['success' => false, 'message' => '文件写入失败'];
        }
        
        // 保存到数据库
        $fileUrl = $uploadUrl . '/' . $filePath;
        $fileRecord = $this->saveFileRecord($file, $filePath, $fileUrl, $config->id, $module, $action, $md5, $sha1);
        
        return [
            'success' => true,
            'file_id' => $fileRecord->id,
            'file_url' => $fileUrl,
            'file_name' => $fileName,
            'original_name' => $file->getInfo('name'),
            'file_size' => $file->getSize(),
            'file_type' => $file->getMime()
        ];
    }
    
    /**
     * 上传到七牛云
     */
    protected function uploadToQiniu($content, $filePath, $fileName, $file, $config, $module, $action, $md5, $sha1)
    {
        $configData = $config->config;
        
        try {
            // 使用七牛云SDK上传
            $auth = new \Qiniu\Auth($configData['access_key'], $configData['secret_key']);
            $token = $auth->uploadToken($configData['bucket']);
            
            $uploadMgr = new \Qiniu\Storage\UploadManager();
            list($ret, $err) = $uploadMgr->put($token, $fileName, $content);
            
            if ($err !== null) {
                return ['success' => false, 'message' => '七牛云上传失败：' . $err->message()];
            }
            
            // 生成文件URL
            $fileUrl = $configData['domain'] . '/' . $fileName;
            
            // 保存到数据库
            $fileRecord = $this->saveFileRecord($file, $filePath, $fileUrl, $config->id, $module, $action, $md5, $sha1);
            
            return [
                'success' => true,
                'file_id' => $fileRecord->id,
                'file_url' => $fileUrl,
                'file_name' => $fileName,
                'original_name' => $file->getInfo('name'),
                'file_size' => $file->getSize(),
                'file_type' => $file->getMime()
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => '七牛云上传失败：' . $e->getMessage()];
        }
    }
    
    /**
     * 保存文件记录到数据库
     */
    protected function saveFileRecord($file, $filePath, $fileUrl, $configId, $module, $action, $md5, $sha1)
    {
        $data = [
            'config_id' => $configId,
            'original_name' => $file->getInfo('name'),
            'file_name' => basename($filePath),
            'file_path' => $filePath,
            'file_url' => $fileUrl,
            'file_size' => $file->getSize(),
            'file_type' => $file->getMime(),
            'mime_type' => $file->getMime(),
            'extension' => strtolower($file->getOriginalExtension()),
            'md5' => $md5,
            'sha1' => $sha1,
            'upload_module' => $module,
            'upload_action' => $action,
            'user_id' => session('user.id'),
            'admin_id' => session('admin.id'),
            'status' => 1
        ];
        
        return \app\admin\model\yuncunchu\File::create($data);
    }

    /**
     * 多文件上传
     */
    public function batch()
    {
        // 直接使用PHP的$_FILES，避免ThinkPHP的文件处理
        if (!isset($_FILES['files']) || !is_array($_FILES['files']['name'])) {
            $this->error('请选择要上传的文件');
        }
        
        $uploadedFiles = [];
        $fileCount = count($_FILES['files']['name']);
        
        // 重新组织文件数组
        for ($i = 0; $i < $fileCount; $i++) {
            if ($_FILES['files']['error'][$i] === UPLOAD_ERR_OK) {
                $uploadedFiles[] = [
                    'name' => $_FILES['files']['name'][$i],
                    'type' => $_FILES['files']['type'][$i],
                    'tmp_name' => $_FILES['files']['tmp_name'][$i],
                    'error' => $_FILES['files']['error'][$i],
                    'size' => $_FILES['files']['size'][$i]
                ];
            }
        }
        
        if (empty($uploadedFiles)) {
            $this->error('没有有效的文件上传');
        }
        
        $configId = $this->request->post('config_id');
        $module = $this->request->post('module', 'admin');
        $action = $this->request->post('action', 'upload');
        
        try {
            // 验证每个文件
            foreach ($uploadedFiles as $uploadedFile) {
                // 检查文件大小
                $maxSize = 50 * 1024 * 1024; // 50MB
                if ($uploadedFile['size'] > $maxSize) {
                    $this->error('文件大小超过限制（最大允许：50MB）');
                }
                
                // 检查文件类型
                $allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'zip', 'rar', 'wav', 'mp4', 'mp3', 'webm'];
                $extension = strtolower(pathinfo($uploadedFile['name'], PATHINFO_EXTENSION));
                if (!in_array($extension, $allowedTypes)) {
                    $this->error('不支持的文件类型：' . $extension);
                }
            }
            
            // 直接处理文件，完全避免框架方法
            $results = [];
            foreach ($uploadedFiles as $uploadedFile) {
                $results[] = $this->processDirectFileUpload($uploadedFile, $configId, $module, $action);
            }
            
            $successCount = 0;
            $failedCount = 0;
            $successFiles = [];
            $failedFiles = [];
            
            foreach ($results as $result) {
                if ($result['success']) {
                    $successCount++;
                    $successFiles[] = $result;
                } else {
                    $failedCount++;
                    $failedFiles[] = $result;
                }
            }
            
            $this->success('批量上传完成', null, [
                'success_count' => $successCount,
                'failed_count' => $failedCount,
                'success_files' => $successFiles,
                'failed_files' => $failedFiles
            ]);
        } catch (Exception $e) {
            $this->error('批量上传失败：' . $e->getMessage());
        }
    }

    /**
     * 删除文件
     */
    public function delete()
    {
        $fileId = $this->request->post('file_id');
        
        if (!$fileId) {
            $this->error('请指定要删除的文件');
        }
        
        try {
            $service = new YuncunchuService();
            $service->delete($fileId);
            $this->success('删除成功');
        } catch (Exception $e) {
            $this->error('删除失败：' . $e->getMessage());
        }
    }

    /**
     * 获取文件信息
     */
    public function info()
    {
        $fileId = $this->request->get('file_id');
        
        if (!$fileId) {
            $this->error('请指定文件ID');
        }
        
        $file = \app\admin\model\yuncunchu\File::with(['config'])->find($fileId);
        
        if (!$file) {
            $this->error('文件不存在');
        }
        
        $this->success('获取成功', null, $file);
    }

    /**
     * 获取上传配置
     */
    public function config()
    {
        $configs = \app\admin\model\yuncunchu\Config::where('status', 1)->select();
        $defaultConfig = \app\admin\model\yuncunchu\Config::getDefaultConfig();
        
        $this->success('获取成功', null, [
            'configs' => $configs,
            'default_config' => $defaultConfig
        ]);
    }
}
